<?php
/* MyMeeting is an online meeting management software.
 * Copyright (C) 2009 Government Of Malaysia
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * @author: Abdullah Zainul Abidin, Nuhaa All Bakry
 *          Eavay Javay Barnad, Sarogini Muniyandi, Teow Jit Huan
 *
 */

class Decision extends AppModel {

    /**
     * Defining the name of model
     *
     */
    var $name = 'Decision';
    /**
     * Defining the name of the table
     *
     */
    var $useTable = 'decisions';
    /**
     * Defining behavior in the model
     *
     */
    var $actsAs = array('MultiFile','Comment','Containable','Tree');

    //The Associations below have been created with all possible keys, those that are not needed can be removed
    /**
     * Building assosiations betweeen models
     *
     */
    var $belongsTo = array(
        'Committee' => array(
            'className' => 'Committee',
            'foreignKey' => 'committee_id',
            'conditions' => '',
        'limit' => '25',
            'fields' => '',
            'order' => ''),
        'Meeting' => array(
            'className' => 'Meeting',
            'foreignKey' => 'meeting_id',
            'conditions' => '',
            'fields' => '',
            'order' => ''),
        'Item' => array(
            'className' => 'Item',
            'foreignKey' => 'item_id',
            'conditions' => '',
            'fields' => '',
            'order' => '')
        );

    /**
     * Build the association between the Decision and Userstatus,Decision and Groupstatus
     *
     */
    var $hasMany = array(
        'Userstatus' => array(
            'className' => 'Userstatus',
            'foreignKey' => 'decision_id',
            'dependent' => false,
            'conditions' => '',
            'fields' => '',
            'group'=>'Decision.user_id',
            'order' => 'Userstatus.updated desc',
            'limit' => '',
            'offset' => '',
            'exclusive' => '',
            'finderQuery' => '',
            'counterQuery' => ''
        ),
        'Groupstatus' => array(
            'className' => 'Groupstatus',
            'foreignKey' => 'decision_id',
            'dependent' => false,
            'conditions' => '',
            'fields' => '',
            'group'=>'Decision.group_id',
            'order' => 'Groupstatus.updated desc',
            'limit' =>'',
            'offset' => '',
            'exclusive' => '',
            'finderQuery' => '',
            'counterQuery' => '')
        );

    /**
     * Building assosiations betweeen models
     *
     */
    var $hasAndBelongsToMany = array(
        'User' => array(
            'className' => 'User',
            'joinTable' => 'decisions_users',
            'foreignKey' => 'decision_id',
            'associationForeignKey' => 'user_id',
            'unique' => true,
            'conditions' => '',
            'fields' => '',
            'order' => '',
            'limit' => '',
            'offset' => '',
            'finderQuery' => '',
            'deleteQuery' => '',
            'insertQuery' => ''),
        'Group' => array(
            'className' => 'Group',
            'joinTable' => 'decisions_groups',
            'foreignKey' => 'decision_id',
            'associationForeignKey' => 'group_id',
            'unique' => true,
            'conditions' => '',
            'fields' => '',
            'order' => '',
            'limit' => '',
            'offset' => '',
            'finderQuery' => '',
            'deleteQuery' => '',
            'insertQuery' => '')
        );

    /**
     * Finding all the related users defined by the decicion id
     * $param decision_id finds all the related users
     */
    function getUser($id){
        $ddat=mysql_fetch_assoc(mysql_query("select name, job_title from users where id=$id"));
        return $ddat;
    }

    /**
     * Finding all the users decisions defined by the decision id
     * $param decision_id and user_id finds all the related users decisions
     */
    function individualImplementors($id){
        return Set::extract($this->DecisionsUser->getData(array('user_id'),array('decision_id'=>$id)),'{n}.DecisionsUser.user_id');
    }

    /**
     * Finding all the groups decisions defined by the decision id
     * $param decision_id and group_id finds all the related groups decisions
     */
    function groupImplementors($id){
        return Set::extract($this->DecisionsGroup->getData(array('group_id'),array('decision_id'=>$id)),'{n}.DecisionsGroup.group_id');
    }

    function getMinutes($text){
        $pattern='style="[^"]*"';
        $replacement='';
        $text=eregi_replace($pattern,$replacement,$text);
        $decisions=explode("###",$text);
        $implpattern="|{{(.*)}}|sU";
        foreach($decisions as $curdecision){
            $numimpl=preg_match_all($implpattern,$curdecision,$implname);
            if($numimpl){
                $toret[]=trim($curdecision);
            }
        }
        if(isset($toret)){
            return $toret;
        }
        else{
            return false;
        }
    }

    /**
     * Finding all the minutes
     *
     * Will try to find all the minutes in a html formatted text. 
     * Minutes are defined as an item which contains at least 
     * one reference to the user (ie: find {{username}} enclosed in a pair of ###)
     *
     * @param text - The raw data (html formatted) where the decision might come from
     * @return array containing all the minutes extracted where each row is 1 minute
     *
     */
    function extractMinutes($text){
        $dcurdat=null;
        $decisions=$this->getMinutes($text);
        if (!empty($decisions) && isset($decisions)){
        foreach($decisions as $draw){
            $ddat=strip_tags($draw,'<li><p><br>');
            $projpattern="|\[\[(.*)\]\]|sU";
            $implpattern="|{{(.*)}}|sU";
            $dtlnpattern="|\(\((.*)\)\)|sU";
            $numproject=preg_match($projpattern,$ddat,$projectname);
            if($numproject){
                $curdat['Item']=$projectname[1];
            }
            else{
                $curdat['Item']=null;
            }
            $numimpl=preg_match_all($implpattern,$ddat,$implname);
            if($numimpl){
                if(isset($dnames)) unset($dnames);
                foreach($implname[1] as $imname){
                    if(isset($dnames)){
                        $dnames=array_merge($dnames,explode(',',$imname));
                    }
                    else{
                        $dnames=explode(',',$imname);
                    }
                }
                $curdat['User']=array_merge($dnames);
            }
            else{
                $curdat['User']=null;
            }
            $numdtln=preg_match($dtlnpattern,$ddat,$dtlnname);
            if($numdtln){
                $curdat['Dateline']=$dtlnname[1];
            }
            else{
                $curdat['Dateline']=null;
            }
            $eddat=preg_replace($implpattern,"\$1",$ddat);
            $eddat=preg_replace($projpattern,"\$1",$eddat);
            $eddat=preg_replace($dtlnpattern,"\$1",$eddat);
            $curdat['Decision']=$eddat;
            $curdat['OriDecision']=$draw;
            $dcurdat[]=$curdat;
        }
    }
        return $dcurdat;
    }

    /* Extract data from text. Legend is:
     * ### is decision separator.
     * [[project/item]] 
     * {{implementor}}
     * ((dateline))
     */
    function extractText($text){
        $decisions=explode("###",$text);
        foreach($decisions as $ddat){
            $projpattern="|\[\[(.*)\]\]|U";
            $implpattern="|{{(.*)}}|U";
            $dtlnpattern="|\(\((.*)\)\)|U";
            $numproject=preg_match($projpattern,$ddat,$projectname);
            if($numproject){
                $curdat['Item']=$projectname[1];
            }
            else{
                $curdat['Item']=null;
            }
            $numimpl=preg_match_all($implpattern,$ddat,$implname);
            if($numimpl){
                if(isset($dnames)) unset($dnames);
                foreach($implname[1] as $imname){
                    if(isset($dnames)){
                        $dnames=array_merge($dnames,explode(',',$imname));
                    }
                    else{
                        $dnames=explode(',',$imname);
                    }
                }
                $curdat['User']=array_merge($dnames);
            }
            else{
                $curdat['User']=null;
            }
            $numdtln=preg_match($dtlnpattern,$ddat,$dtlnname);
            if($numdtln){
                $curdat['Dateline']=$dtlnname[1];
            }
            else{
                $curdat['Dateline']=null;
            }
            $eddat=preg_replace($implpattern,"\$1",$ddat);
            $eddat=preg_replace($projpattern,"\$1",$eddat);
            $eddat=preg_replace($dtlnpattern,"\$1",$eddat);
            $curdat['Decision']=$eddat;
            $dcurdat[]=$curdat;
        }
        return $dcurdat;
    }

    function itemList($data,$committee_id){
        $defaultlist=Set::extract($this->Item->find('all',array('contain'=>false,'fields'=>array('Item.id','Item.short_name'),'conditions'=>array('Item.committee_id'=>$committee_id))),'{n}.Item');
        foreach($data as $cid=>$curdat){
            $items=$curdat['Item'];
            if(count($items)){
                //we have found something so lets fixup the line of items
                if(isset($curret)) unset($curret);
                $current=array();
                foreach($items as $citem){
                    $cur['id']=$citem['Item']['id'];
                    $cur['short_name']=$citem['Item']['short_name'];
                    $curret[]=$cur;
                }
                $thislist=Set::extract($this->Item->find('all',array('contain'=>false,'fields'=>array('id','short_name'),'conditions'=>array('committee_id'=>$committee_id,'not'=>array('id'=>Set::extract($curret,'{n}.id'))))),'{n}.Item');
                $data[$cid]['Item']=array_merge($curret,$thislist);
            }
            else{
                //we found nothing before this. Just get the whole amount of items
                $data[$cid]['Item']=$defaultlist;
                $data[$cid]['noitem']=true;
            }
        }
        return $data;
    }

    function groupList($data,$committee_id){
        $defaultlist=Set::extract($this->Group->find('all',array('contain'=>false,'fields'=>array('id','name'),'conditions'=>array('committee_id'=>$committee_id))),'{n}.Group');
        foreach($data as $cid=>$curdat){
            $groups=$curdat['Group'];
            if(count($groups)){
                foreach($groups as $uid=>$udata){
                    if(count($udata)){
                        //we have found something so lets fixup the line of groups
                        if(isset($curret)) unset($curret);
                        foreach($udata as $cuser){
                            $cur['id']=$cuser['Group']['id'];
                            $cur['name']=$cuser['Group']['name'];
                            $curret[]=$cur;
                        }
                        $thislist=Set::extract($this->Group->find('all',array(
                            'contain'=>false,
                            'fields'=>array('id','name'),
                            'conditions'=>array(
                                'committee_id'=>$committee_id,
                                'not'=>array('id'=>Set::extract($curret,'{n}.id')),
                            )
                        )),'{n}.Group');
                        $data[$cid]['Group'][$uid]=array_merge($curret,$thislist);
                    }
                    else{
                        //we found nothing before this. Just get the whole amount of groups
                        $data[$cid]['Group'][$uid]=$defaultlist;
                        $data[$cid]['nogroup'][$uid]=true;
                    }
                }
            }
        }
        return $data;
    }

    function userList($data,$committee_id){
        $defaultlist=Set::extract($this->Committee->find('all',array(
            'contain'=>array(
                'User'=>array(
                    'fields'=>array('id','name'),
                    'order'=>array('name'),
                ),
            ),
            'conditions'=>array(
                'id'=>$committee_id,
            )
        )),'{n}.User');
        $defaultlist=$defaultlist[0];
        foreach($defaultlist as $cid=>$cdata){
            unset($defaultlist[$cid]['Membership']);
        }
        foreach($data as $cid=>$curdat){
            $users=$curdat['User'];
            if(count($users)){
                foreach($users as $uid=>$udata){
                    if(count($udata)){
                        //we have found something so lets fixup the line of users
                        if(isset($curret)) unset($curret);
                        foreach($udata as $cuser){
                            $cur['id']=$cuser['User']['id'];
                            $cur['name']=$cuser['User']['name'];
                            $curret[]=$cur;
                        }
                        $thislist=Set::extract($this->Committee->find('all',array(
                            'contain'=>array(
                                'User'=>array(
                                    'fields'=>array('id','name'),
                                    'order'=>array('name'),
                                    'conditions'=>array('not'=>array('User.id'=>Set::extract($curret,'{n}.id'))),
                                ),
                            ),
                            'conditions'=>array(
                                'id'=>$committee_id,
                            )
                        )),'{n}.User');
                        $thislist=$thislist[0];
                        foreach($thislist as $xjcid=>$xjcdata){
                            unset($thislist[$xjcid]['Membership']);
                        }
                        $data[$cid]['User'][$uid]=array_merge($curret,$thislist);
                    }
                    else{
                        //we found nothing before this. Just get the whole amount of users
                        $data[$cid]['User'][$uid]=$defaultlist;
                        $data[$cid]['nouser'][$uid]=true;
                    }
                }
            }
        }
        return $data;
    }


    function filterData($data,$meeting_id=null){
        $comid=$this->Meeting->getCommitteeId($meeting_id);
        $allret=array();
        foreach($data as &$cdat){
            /* Get all the possible items first. Search by short name first then by name.Filter by committee_id */
            if($cdat['Item']){
                $cdat['Item']=trim($cdat['Item']);
                $ditem=$this->Item->getData(array('Item.id','Item.short_name','Item.name'),array('Item.committee_id'=>$comid,'or'=>array('Item.short_name like \'%'.$cdat['Item'].'%\'','Item.name like \'%'.$cdat['Item'].'%\'')));
                if(count($ditem)){
                    $retdat['Item']=$ditem;
                }
                else{
                    /*didn't find any item/projects. Try harder. Maybe the user misspelled parts of the name. Break the data into 4 parts and check for each part*/
                    $partlen=strlen($cdat['Item'])/4;
                    if($partlen>1){  //only search if it is worth it
                        $part[0]=substr($cdat['Item'],0,$partlen);
                        $part[1]=substr($cdat['Item'],$partlen,$partlen);
                        for($i=0;$i<4;$i++){
                            $part[$i]=substr($cdat['Item'],$i*$partlen,($i+1)*$partlen);
                            $dsql[]='Item.short_name like \'%'.$part[$i].'%\'';
                            $dsql[]='Item.name like \'%'.$part[$i].'%\'';
                            $dcond[]=array('or'=>$dsql);
                            unset($dsql);
                        }
                        $ditem=$this->Item->getData(array('Item.id','Item.short_name','Item.name'),array('Item.committee_id'=>$comid,'or'=>$dcond));
                        $retdat['Item']=$ditem;
                    }
                    else{
                        $retdat['Item']=null;
                    }
                    unset($dcond);
                }
                if(strlen($cdat['Item'])>1){
                    $retdat['LostItem']=$cdat['Item'];
                }
                else{
                    $retdat['LostItem']=null;
                }
            }
            else{
                $retdat['Item']=null;
                $retdat['LostItem']=null;
            }

            /* Look for users */
            if(isset($puser)) unset($puser);
            $comuser=Set::extract($this->User->Membership->getData(array('Membership.user_id'),array('Membership.committee_id'=>$comid)),'{n}.Membership.user_id');
            if(isset($cdat['User']) && count($cdat['User'])){
                foreach($cdat['User'] as $cuser){
                    $cuser=trim($cuser);
                    $source="user";
                    if(substr(strtolower($cuser),0,2)=="g:"){
                        $source="group";
                        $cuser=substr($cuser,2);
                    }
                    if($source=="user"){
                        $dname=$this->User->getData(array('id','name'),array('User.id'=>$comuser,'or'=>array('User.username like \'%'.$cuser.'%\'','User.name like \'%'.$cuser.'%\'')));
                        $found=false;
                        if(count($dname)){
                            $puser[]=$dname;
                            $found=true;
                        }
                        else{
                            /*didn't find any users. Try harder. Maybe the user misspelled parts of the name. Break the data into 4 parts and check for each part*/
                            $partlen=strlen($cuser)/4;
                            if($partlen>1){
                                $part[0]=substr($cuser,0,$partlen);
                                $part[1]=substr($cuser,$partlen,$partlen);
                                for($i=0;$i<4;$i++){
                                    $part[$i]=substr($cuser,$i*$partlen,($i+1)*$partlen);
                                    $dsql[]='username like \'%'.$part[$i].'%\'';
                                    $dsql[]='name like \'%'.$part[$i].'%\'';
                                    $dcond[]=array('or'=>$dsql);
                                    unset($dsql);
                                }
                                $ditem=$this->User->getData(array('id','name'),array('id'=>$comuser,'or'=>$dcond));
                                if(count($ditem)){
                                    $puser[]=$ditem;
                                    $found=true;
                                }
                            }
                            unset($dcond);
                        }
                        if(!$found){
                            $puser[]=null;
                        }
                    }
                    else{
                        $dgroup=$this->Group->getData(array('id','name'),array('committee_id'=>$comid,'Group.name like \'%'.$cuser.'%\''));
                        $found=false;
                        if(count($dgroup)){
                            $pgroup[]=$dgroup;
                            $found=true;
                        }
                        else{
                            /*didn't find any users. Try harder. Maybe the user misspelled parts of the name. Break the data into 4 parts and check for each part*/
                            $partlen=strlen($cuser)/4;
                            if($partlen>1){
                                $part[0]=substr($cuser,0,$partlen);
                                $part[1]=substr($cuser,$partlen,$partlen);
                                for($i=0;$i<4;$i++){
                                    $part[$i]=substr($cuser,$i*$partlen,($i+1)*$partlen);
                                    $dsql[]='name like \'%'.$part[$i].'%\'';
                                    $dcond[]=array('or'=>$dsql);
                                    unset($dsql);
                                }
                                $ditem=$this->Group->getData(array('id','name'),array('committee_id'=>$comid,'or'=>$dcond));
                                if(count($ditem)){
                                    $pgroup[]=$ditem;
                                    $found=true;
                                }
                            }
                            unset($dcond);
                        }
                        if(!$found){
                            $pgroup[]=null;
                        }
                    }
                }
            }
            if(isset($puser)){
                $retdat['User']=$puser;
                unset($puser);
            }
            else{
                $retdat['User']=null;
            }
            if(isset($pgroup)){
                $retdat['Group']=$pgroup;
                unset($pgroup);
            }
            else{
                $retdat['Group']=null;
            }

            /* The date has to be translated into something the system can use */
            $ddate=$this->translateDate($cdat['Dateline']);
            $retdat['Dateline']=$ddate;
            $retdat['Decision']=$cdat['Decision'];
            $retdat['OriDecision']=$cdat['OriDecision'];
            $allret[]=$retdat;
        }
        return $allret;
    }


    function translateDate($date){
        /* Just return it back for now */
        $delimiter=array('/','-');
        foreach($delimiter as $d){
            if(strpos($date,$d)!==false){
                $limit=$d;
                break;
            }
        }
        if(isset($limit)){
            $parts=explode($limit,$date);
            if(count($parts)==3){
                if(strlen($parts[0])==2 && strlen($parts[2])==4){   //correct length of parts but the other way around
                    $tmp=$parts[0];
                    $parts[0]=$parts[2];
                    $parts[2]=$tmp;
                    return implode('-',$parts);
                }
                elseif(strlen($parts[2])==2 && strlen($parts[0])==4){  //correct length and right order
                    return implode('-',$parts);
                }
                else{  //else assume short malaysian way of writing date (ie dd/mm/yy)
                    $tmp=$parts[0];
                    $parts[0]=$parts[2];
                    $parts[2]=$tmp;
                    $parts[0]='20'.$parts[0];
                    return implode('-',$parts);
                }
            }
        }
        return false;
    }

    /**
     * Getting the current userstatus and groupstatusfor the decision
     */
    function getCurrentStatus($id){
        $prefix=$this->tablePrefix;
        $finder= 'SELECT `Userstatus`.`id`, `Userstatus`.`decision_id`, `Userstatus`.`user_id`, `Userstatus`.`description`, `Userstatus`.`action_date`, `Userstatus`.`deleted`, `Userstatus`.`deleted_date`, `Userstatus`.`created`, `Userstatus`.`updated`,`Userstatus`.`approved`, `User`.`id`, `User`.`username`, `User`.`superuser`, `User`.`job_title`, `User`.`name`, `User`.`email`, `User`.`telephone`, `User`.`mobile`, `User`.`fax`, `User`.`address`, `User`.`title_id`, `User`.`deleted`, `User`.`deleted_date` FROM `'.$prefix.'userstatuses` AS `Userstatus` LEFT JOIN `'.$prefix.'decisions` AS `Decision` ON (`Userstatus`.`decision_id` = `Decision`.`id`) LEFT JOIN `'.$prefix.'users` AS `User` ON (`Userstatus`.`user_id` = `User`.`id`) LEFT OUTER JOIN `'.$prefix.'userstatuses` as `s2` on (`Userstatus`.`user_id`=`s2`.`user_id` and `Userstatus`.`updated`<`s2`.`updated` and `Userstatus`.`decision_id`=`s2`.`decision_id`) WHERE `Userstatus`.`decision_id` = {$__cakeID__$} and `s2`.`id` is null';
        $gfinder= 'SELECT `Groupstatus`.`id`, `Groupstatus`.`decision_id`, `Groupstatus`.`user_id`, `Groupstatus`.`group_id`, `Groupstatus`.`description`, `Groupstatus`.`action_date`, `Groupstatus`.`deleted`, `Groupstatus`.`deleted_date`, `Groupstatus`.`created`, `Groupstatus`.`updated`,`Groupstatus`.`approved`, `Group`.`id`, `Group`.`name`, `User`.`id`, `User`.`username`, `User`.`superuser`, `User`.`job_title`, `User`.`name`, `User`.`email`, `User`.`telephone`, `User`.`mobile`, `User`.`fax`, `User`.`address`, `User`.`title_id`, `User`.`deleted`, `User`.`deleted_date` FROM `'.$prefix.'groupstatuses` AS `Groupstatus` LEFT JOIN `'.$prefix.'decisions` AS `Decision` ON (`Groupstatus`.`decision_id` = `Decision`.`id`) LEFT JOIN `'.$prefix.'users` AS `User` ON (`Groupstatus`.`user_id` = `User`.`id`) LEFT JOIN `'.$prefix.'groups` AS `Group` ON (`Groupstatus`.`group_id` = `Group`.`id`) LEFT OUTER JOIN `'.$prefix.'groupstatuses` as `s2` on (`Groupstatus`.`group_id`=`s2`.`group_id` and `Groupstatus`.`updated`<`s2`.`updated` and `Groupstatus`.`decision_id`=`s2`.`decision_id`) WHERE `Groupstatus`.`decision_id` = {$__cakeID__$} and `s2`.`id` is null';
        $this->bindModel(
            array(
                'hasMany'=>array(
                    'Userstatus'=>array(
                        'className' => 'Userstatus',
                        'foreignKey' => 'decision_id',
                        'dependent' => false,
                        'conditions' => '',
                        'fields' => '',
                        'order' => '',
                        'limit' => '',
                        'offset' => '',
                        'exclusive' => '',
                        'finderQuery' => $finder,
                        'counterQuery' => ''),
                    'Groupstatus'=>array(
                        'className' => 'Groupstatus',
                        'foreignKey' => 'decision_id',
                        'dependent' => false,
                        'conditions' => '',
                        'fields' => '',
                        'order' => '',
                        'limit' => '',
                        'offset' => '',
                        'exclusive' => '',
                        'finderQuery' => $gfinder,
                        'counterQuery' => '')
                    )
                )
            );
        return $this->read(null, $id);
    }


    /**
     * Bind the decision model to select only the latest status from each user and group
     */
    function bindLatest(){
        $db =& ConnectionManager::getDataSource($this->useDbConfig);
        $finder= 'SELECT `Userstatus`.`id`, `Userstatus`.`decision_id`, `Userstatus`.`user_id`, `Userstatus`.`description`, `Userstatus`.`action_date`, `Userstatus`.`deleted`, `Userstatus`.`deleted_date`, `Userstatus`.`created`, `Userstatus`.`updated`, `User`.`id`, `User`.`username`, `User`.`superuser`, `User`.`job_title`, `User`.`name`, `User`.`email`, `User`.`telephone`, `User`.`mobile`, `User`.`fax`, `User`.`address`, `User`.`title_id`, `User`.`deleted`, `User`.`deleted_date` FROM '.$db->fullTableName('userstatuses').' AS `Userstatus` LEFT JOIN '.$db->fullTableName('decisions').' AS `Decision` ON (`Userstatus`.`decision_id` = `Decision`.`id`) LEFT JOIN '.$db->fullTableName('users').' AS `User` ON (`Userstatus`.`user_id` = `User`.`id`) LEFT OUTER JOIN '.$db->fullTableName('userstatuses').' as `s2` on (`Userstatus`.`user_id`=`s2`.`user_id` and `Userstatus`.`updated`<`s2`.`updated` and `Userstatus`.`decision_id`=`s2`.`decision_id`) WHERE `Userstatus`.`decision_id` in ( {$__cakeID__$} ) and `s2`.`id` is null';
        $gfinder= 'SELECT `Groupstatus`.`id`, `Groupstatus`.`decision_id`, `Groupstatus`.`user_id`, `Groupstatus`.`group_id`, `Groupstatus`.`description`, `Groupstatus`.`action_date`, `Groupstatus`.`deleted`, `Groupstatus`.`deleted_date`, `Groupstatus`.`created`, `Groupstatus`.`updated`, `Group`.`id`, `Group`.`name`, `User`.`id`, `User`.`username`, `User`.`superuser`, `User`.`job_title`, `User`.`name`, `User`.`email`, `User`.`telephone`, `User`.`mobile`, `User`.`fax`, `User`.`address`, `User`.`title_id`, `User`.`deleted`, `User`.`deleted_date` FROM '.$db->fullTableName('groupstatuses').' AS `Groupstatus` LEFT JOIN '.$db->fullTableName('decisions').' AS `Decision` ON (`Groupstatus`.`decision_id` = `Decision`.`id`) LEFT JOIN '.$db->fullTableName('users').' AS `User` ON (`Groupstatus`.`user_id` = `User`.`id`) LEFT JOIN '.$db->fullTableName('groups').' AS `Group` ON (`Groupstatus`.`group_id` = `Group`.`id`) LEFT OUTER JOIN '.$db->fullTableName('groupstatuses').' as `s2` on (`Groupstatus`.`group_id`=`s2`.`group_id` and `Groupstatus`.`updated`<`s2`.`updated` and `Groupstatus`.`decision_id`=`s2`.`decision_id`) WHERE `Groupstatus`.`decision_id` in ( {$__cakeID__$} ) and `s2`.`id` is null';
        $this->bindModel(
            array(
                'hasMany'=>array(
                    'Userstatus'=>array(
                        'className' => 'Userstatus',
                        'foreignKey' => 'decision_id',
                        'dependent' => false,
                        'conditions' => '',
                        'fields' => '',
                        'order' => '',
                        'limit' => '',
                        'offset' => '',
                        'exclusive' => '',
                        'finderQuery' => $finder,
                        'counterQuery' => ''),
                    'Groupstatus'=>array(
                        'className' => 'Groupstatus',
                        'foreignKey' => 'decision_id',
                        'dependent' => false,
                        'conditions' => '',
                        'fields' => '',
                        'order' => '',
                        'limit' => '',
                        'offset' => '',
                        'exclusive' => '',
                        'finderQuery' => $gfinder,
                        'counterQuery' => '')
                    )
                )
            );
    }

    /**
     * Finding all the search
     */
    function search($field) {
        if ($field['from']=='items/view') {   
            $cond['Decision.item_id'] = $field['item_id'];
            if (isset($field['meeting']) && !empty($field['meeting'])) {
                $cond['Decision.meeting_id']= $field['meeting'];
            }
        }
        else if ($field['from']=='meetings/view'){
            $cond['Decision.meeting_id']=$field['meeting_id'];
            if (isset($field['item']) && !empty($field['item'])) {
                $cond['Decision.item_id']=$field['item'];
           }
        }         
        if (isset($field['group']) && !empty($field['group'])) {
            $decisionGroup=array();
            $decisionGroup=Set::extract($this->DecisionsGroup->find('all',array('conditions'=>array('DecisionsGroup.group_id'=>$field['group']))),'{n}.DecisionsGroup.decision_id');
        }
        if (isset($field['user']) && !empty($field['user'])) {
            $decisionUser=array();
            $decisionUser=Set::extract($this->DecisionsUser->find('all',array('conditions'=>array('DecisionsUser.user_id'=>$field['user']))),'{n}.DecisionsUser.decision_id');
        }
        if(!empty($field['group']) || !empty($field['user'])){
            if(empty($field['group'])){
                $cond['Decision.id']=$decisionUser;
            }elseif(empty($field['user'])){
                $cond['Decision.id']=$decisionGroup;
            }else{
                $cond['Decision.id']=array_intersect($decisionUser,$decisionGroup);
            }
        }
        $decision=$this->find('all',array('conditions'=>$cond));
        return $decision;
    }

    function promote($id){
        $this->unbindModel(array('hasAndBelongsToMany'=>array('User','Group')),false);
        $decision=$this->find('first',array(
            'conditions'=>array(
                'Decision.id'=>$id,
            )
        ));
        $prevnumber=$this->find('first',array(
            'conditions'=>array(
                'Decision.meeting_id'=>$decision['Decision']['meeting_id'],
                'Decision.ordering<'.$decision['Decision']['ordering'],
                'Decision.deleted=0',
            ),
            'order'=>array(
                'Decision.ordering desc'
            ),
            'contain'=>false,
            'fields'=>array(
                'ordering',
            ),
        ));
        if(isset($prevnumber['Decision']['ordering'])){
            /** This is to jump over all of the decisions with the same decision ordering. Shouldn't happen too often **/
            $prev=$this->find('all',array(
                'conditions'=>array(
                    'Decision.meeting_id'=>$decision['Decision']['meeting_id'],
                    'Decision.ordering'=>$prevnumber['Decision']['ordering'],
                )
            ));
            if(count($prev)>1){
                $curprev=$prev[0]['Decision']['ordering'];
                foreach($prev as $curprev){
                    $curprev['Decision']['ordering']=$decision['Decision']['ordering'];
                    $this->save($curprev);
                }
                $decision['Decision']['ordering']=$curprev;
                $this->save($decision);
            }
            elseif(count($prev)){
                $curprev=$prev[0]['Decision']['ordering'];
                $prev[0]['Decision']['ordering']=$decision['Decision']['ordering'];
                $this->save($prev[0]);
                $decision['Decision']['ordering']=$curprev;
                $this->save($decision);
            }
        }
        else{
            $decision['Decision']['ordering']-=1;
            $this->save($decision);
        }
    }

    function demote($id){
        $this->unbindModel(array('hasAndBelongsToMany'=>array('User','Group')),false);
        $decision=$this->find('first',array(
            'conditions'=>array(
                'Decision.id'=>$id,
            )
        ));
        $nextnumber=$this->find('first',array(
            'conditions'=>array(
                'Decision.meeting_id'=>$decision['Decision']['meeting_id'],
                'Decision.ordering>'.$decision['Decision']['ordering'],
                'Decision.deleted=0',
            ),
            'order'=>array(
                'Decision.ordering asc'
            ),
            'contain'=>false,
            'fields'=>array(
                'ordering',
            ),
        ));
        if(isset($nextnumber['Decision']['ordering'])){
            $next=$this->find('all',array(
                'conditions'=>array(
                    'Decision.meeting_id'=>$decision['Decision']['meeting_id'],
                    'Decision.ordering'=>$nextnumber['Decision']['ordering'],
                )
            ));
            if(count($next)>1){
                $curnext=$next[0]['Decision']['ordering'];
                foreach($next as $ndec){
                $ndec['Decision']['ordering']=$decision['Decision']['ordering'];
                $this->save($ndec);
                }
                $decision['Decision']['ordering']=$curnext;
                $this->save($decision);
            }
            elseif(count($next)){
                $curnext=$next[0]['Decision']['ordering'];
                $next[0]['Decision']['ordering']=$decision['Decision']['ordering'];
                $this->save($next[0]);
                $decision['Decision']['ordering']=$curnext;
                $this->save($decision);
            }
        }
        else{
            $decision['Decision']['ordering']+=1;
            $this->save($decision);
        }
    }

	//inform a decision to the implementors
    function notifyuser($id){
        $decision=$this->find('first',array(
            'conditions'=>array(
                'Decision.id'=>$id,
            ),
        ));
        $decision['Link']['decision']=array('committee'=>urlencode($decision['Committee']['short_name']),'controller'=>'decisions','action'=>'view','id'=>$id);
    
        $this->Template=& ClassRegistry::init('Template');
        $template=$this->Template->processTemplate('decision assigned',$decision);
        $template['Template']['template']=str_replace(array('%%content to repeat','content to repeat%%'),'', $template['Template']['template']);
        if($template){
            $users=$this->decisionimplementor($id);
            if(isset($users)){
                foreach($users as $userid){
                    $user=$this->Meeting->User->find('first',array('conditions'=>array('User.id'=>$userid)));
                    $this->Meeting->sendEmail($decision['Meeting'],$template,$user['User'],Null);
                }
            }
        }
    }
    
    //the user id of all decision implementors
    function decisionimplementor($id){
		$users=$this->individualImplementors($id);
        $groups=$this->groupImplementors($id);
        if(!empty($groups)){
			$users=array_unique(am(
				$users,
                call_user_func_array(
					'array_merge',
                    set::extract(
						$this->User->Group->find('all',array('conditions'=>array('Group.id'=>$groups))),
                        '{n}.User.{n}.id'
                    )
                )
			));
		}
		return $users;
	}
    
    //send email to all implementors of all decision in a meeting
    function notifyalluser($meeting_id){
        $decisions=$this->find('all',array(
            'conditions'=>array(
                'Decision.meeting_id'=>$meeting_id,
            ),
        ));
        $this->Template=& ClassRegistry::init('Template');
        $dec['Meeting']=$decisions[0]['Meeting'];
        $template=$this->Template->processTemplate('decision assigned',$dec);
        $pos1=strpos($template['Template']['template'],'%%content to repeat');
        $pos2=strpos($template['Template']['template'],'content to repeat%%');
        $len=strlen('%%content to repeat');
        $content_repeat=substr($template['Template']['template'],$pos1+$len,$pos2-$pos1-$len);
        
        foreach( $decisions as $d=>$decision){
			$decision['Link']['decision']=array('committee'=>urlencode($decision['Committee']['short_name']),'controller'=>'decisions','action'=>'view','id'=>$decision['Decision']['id']);
			$impls=$this->decisionimplementor($decision['Decision']['id']);
			foreach($impls as $imp){
				$recipient[$imp][]=$decision;
			}
		}
		foreach($recipient as $userid=>$manydecisions){
			$template1=$template;
			$content='';
			foreach($manydecisions as $m){
				$content.=$this->replacetemplate($content_repeat,$m);
			}
			$template1['Template']['template']=str_replace('%%content to repeat'.$content_repeat.'content to repeat%%',$content,$template1['Template']['template']);
			$user=$this->Meeting->User->find('first',array('conditions'=>array('User.id'=>$userid)));
            $this->Meeting->sendEmail($dec['Meeting'],$template1,$user['User'],Null);
		}
    }


    
    function getLevels($meetingid){
        
        $decisionids = $this->find('list',array('conditions'=>array('meeting_id'=>$meetingid)));
        $decisions = $this->generatetreelist(array('id'=>$decisionids), '{n}.Decision.id', '{n}.Decision.id', '_|');
        $levels = array();
        foreach ($decisions as $key=>$value) {
            if (strstr($value, '_|')) {
                // explode anc count how many occurence of _| ==> we get the level
                $temparray = explode('|',$value);
                $levels[$key] = count($temparray) - 1;
            } else {
                $levels[$key] = 0; // top level
            }
        }
        
        return $levels;
    }

    function userdecisionlist($decisions){
        
        $new_decisions = array();
        
        foreach($decisions as $decision){
            
            $UserArray = array();
            $GroupArray = array();
            
            $sql = "SELECT users.name as Name FROM users LEFT JOIN decisions_users ON users.id = decisions_users.user_id WHERE decisions_users.decision_id = ".$decision['Decision']['id'];      
            $result = mysql_query($sql);
            $rows = mysql_num_rows($result);
            if ( $rows > 0 ) {
                while ($gg = mysql_fetch_array($result)) {
                   array_push($UserArray,$gg["Name"] );
                };
            }
            
            $sql = "SELECT groups.name as GroupName FROM groups LEFT JOIN decisions_groups ON groups.id = decisions_groups.group_id WHERE decisions_groups.decision_id = ".$decision['Decision']['id'];      
            $result = mysql_query($sql);
            $rows = mysql_num_rows($result);
            if ( $rows > 0 ) {
                while ($gg = mysql_fetch_array($result)) {
                   array_push($GroupArray,$gg["GroupName"] );
                };
            }
            
            if ( count($UserArray) > 0 ) {
                $decision['Decision']['Userlist'] = array();
                array_push($decision['Decision']['Userlist'],$UserArray);
            }
            
            if ( count($GroupArray) > 0 ) {
                $decision['Decision']['Grouplist'] = array();
                array_push($decision['Decision']['Grouplist'],$GroupArray);
            }
            array_push($new_decisions, $decision);
        }//end looping
        return $new_decisions;
    }
    
    /*
     * Describe check
     * check the no. of approved/not decision, current user is implementor and no updated status
     * @param $decision
     * @param $user_id
     * @return $A (approved decision), $N(not approved decision), $allow (is implementor) ,$noupdated(no updated status)
     */
    function check($decision,$user_id){
        $this->Userstatus->Behaviors->detach('Comment');
        $this->Userstatus->Behaviors->detach('MultiFile');
        $this->Groupstatus->Behaviors->detach('Comment');
        $this->Groupstatus->Behaviors->detach('MultiFile');
        //$A = approved decision
        $A=array_sum(set::extract($decision,'{n}.Decision.approved'));
        //$N = not approved decision
        $N=count($decision)-$A;
        //check whether current user is implementor for decision or not ($allow[$decision['Decision']['id']]>0 means yes)
        $allow=array();
        //check whether current user has update status or not ($noupdated[$decision['Decision']['id']] means no of status didn't been updated)
        $noupdated=array();
        if(count($decision)){
            $committee_id=array_unique(set::extract($decision,'{n}.Decision.committee_id'));
            $group_id=$this->Committee->userGroups($committee_id,$user_id);
            foreach ($decision as $decision){
                $allow[$decision['Decision']['id']]=0;
                $noupdated[$decision['Decision']['id']]=0;
                if(in_array($user_id,set::extract($decision['User'],'{n}.id'))){
                    $allow[$decision['Decision']['id']]++;
                    If(empty($decision['Userstatus'])){
                        $noupdated[$decision['Decision']['id']]++;
                    }else{
                        if(!(in_array($user_id,set::extract($decision['Userstatus'],'{n}.user_id')))){
                            $noupdated[$decision['Decision']['id']]++;
                        }
                    }
                }
                if(!empty($group_id)){
                    if(array_intersect($group_id,set::extract($decision['Group'],'{n}.id'))){
                        $allow[$decision['Decision']['id']]++;
                        if(array_diff(array_intersect($group_id,set::extract($decision['Group'],'{n}.id')),set::extract($decision['Groupstatus'],'{n}.group_id'))){
                            $noupdated[$decision['Decision']['id']]++;
                        }
                    }
                }
            }    
        }
        return array($A,$N,$allow,$noupdated);
    }


    function getArrows($levels, $meetingid){
        $level_array = array('up'=>1, 'down'=>1);
        $new_key = $new_level = $new_level_key = array();
        $total_result = count($levels);
        $i = $ii = $a = 1;
        $mainsum = 0;

        if ( count($levels) > 0 ) {
            foreach ($levels as $key => $level) { array_push($new_key, $key); }

            foreach ($levels as $level) {
                if ( $level == 0 ) { $mainsum++; }
            }
            foreach($levels as $key => $level ){
                $pre = $next = 99;
                $key_value = array_search($key, $new_key);
                $current = $levels[$key];
                if ( $key_value > 0 ) {
                    $pre = $levels[$new_key[$key_value-1]];
                } 
                if ( $i < $total_result ) { 
                    $next = $levels[$new_key[$key_value+1]];
                }
                if ( $pre == 99 && $next == 99 ) {
                    $a = 4;
                } else {
                
                    if ( $ii < $mainsum ) {
                        if ( $pre == 99 ) {
                            $a = 2;
                        }

                        if ( $next == 99 ) {
                            $a = 3;
                        }
                
                        if ( $current > $pre ) {
                            $parent = $this->getparentnode($new_key[$key_value]);
                            $parent = $parent['Decision']['id'];
                            $numberofchild = $this->treeparent($parent, $meetingid);
                            if ( $numberofchild > 1 ) {
                                $a = 2;
                            } else {
                                $a = 4;
                            }   
                        } else {
                            if ( $current > $next ) {
                                $a = 3;
                            }
                        }
                                
                    } else {

                        if ( $current != 0) {
                            $parent = $this->getparentnode($new_key[$key_value]);
                            $parent = $parent['Decision']['id'];
                            $numberofchild = $this->treeparent($parent, $meetingid);
                            if ( $numberofchild > 1 ) {
                                if ( $current > $pre ) {
                                    $a = 2;
                                } 
                                if ( $next == 99 || ($current > $next) ) {
                                    $a = 3;
                                }
                            } else {
                                $a = 4;
                            }
                        } else {
                            $a = 3;
                        }
                    }
                }

                $level_array = array('up'=>1, 'down'=>1);
                if ( $a == 2 ) { $level_array = array('up'=>0, 'down'=>1); }
                if ( $a == 3 ) { $level_array = array('up'=>1, 'down'=>0); }
                if ( $a == 4 ) { $level_array = array('up'=>0, 'down'=>0); }
                array_push($new_level_key, $key);
                array_push($new_level, $level_array);
                if ( $current == 0 ) {
                    $ii++;
                }
                $i++;
                $a = 1;
            }
            return array_combine($new_level_key, $new_level);
        } else {
            return NULL;
        }

        
    }
    

    function treeparent($parent, $meetingid){
        $numberofchild = 0;
        if ( $parent ) {
            $child = $this->query("SELECT lft, rght FROM decisions WHERE id=".$parent);
            $lft = $child[0]['decisions']['lft'];
            $rght = $child[0]['decisions']['rght'];
            $diff = $rght - $lft;

            if ( $diff > 1 ) {
                $childlists = $this->query("SELECT count(id) as total FROM decisions WHERE meeting_id =".$meetingid." AND deleted = 0 AND lft > ".$lft." AND rght <=".$rght );
                $numberofchild = $childlists[0][0]['total'];
            } 
        }
        return $numberofchild;
    }

    function checkMinuteType($committee){
        $minute_type = $this->query("SELECT minutetype.format,minutetype.code FROM committees Committees LEFT JOIN minutetypes minutetype ON minutetype.id = Committees.minutetype_id WHERE Committees.short_name='".$committee."'");
        $minute_type = $minute_type[0]['minutetype'];
        return $minute_type;
    }

    function CommitteeToId($committee){
        $CommitteeId = $this->query("SELECT id FROM committees WHERE short_name = '".$committee."'");
        return $CommitteeId = $CommitteeId[0]['committees']['id'];
    }

    function getMeetingId($decisionID) {
        $MeetingID = $this->query("SELECT meeting_id, lft, rght, parent_id FROM decisions WHERE id =".$decisionID);
        return $MeetingID[0]['decisions'];
    }

    
    function DecisionMoveDown($DecisionId) {
        $detail = $this->getdetails($DecisionId);
        $DownRecord = $this->query("SELECT id, lft, rght FROM decisions WHERE deleted=0 AND meeting_id=".$detail['meeting_id']." AND lft>".$detail['rght']." ORDER BY lft ASC");
        $DownRecord = $DownRecord[0]['decisions'];

        if ( $DownRecord['id'] ) {
            //using moveup to move up the record
            $this->DecisionMoveUp($DownRecord['id']);
        }

    }   

    function DecisionMoveUp($DecisionId){
        $detail = $this->getdetails($DecisionId);
        $UpRecord = $this->query("SELECT id, lft, rght FROM decisions WHERE deleted=0 AND meeting_id=".$detail['meeting_id']." AND rght<".$detail['lft']." ORDER BY rght DESC LIMIT 1");
        $UpRecord = $UpRecord[0]['decisions'];
        $betweens = $this->query("SELECT id FROM decisions WHERE rght < ".$detail['lft']." AND rght > ".$UpRecord['rght']." ORDER BY lft ASC");
        $MinReq = $detail['lft']-$UpRecord['lft'];
        $AddReq = ( $detail['rght'] - $MinReq + 1 ) - $UpRecord['lft'];
        $uplists = $this->TreeListing($detail['lft'], $detail['rght'], $detail['meeting_id']);
        $downlists = $this->TreeListing($UpRecord['lft'], $UpRecord['rght'], $detail['meeting_id'] );

        foreach ( $uplists as $uplist ) {
            $this->UpdateMoveUp($uplist['decisions']['id'], $MinReq);
        }
        
        foreach ($downlists as $downlist ) {
            $this->UpdateMoveDown($downlist['decisions']['id'], $AddReq);
        }

        foreach ( $betweens as $between ) {
            $this->UpdateMoveDown($between['decisions']['id'], $AddReq);
        }
    }

    function TreeListing($lft, $rght, $meeting_id) {
        return $this->query("SELECT id FROM decisions WHERE deleted=0 AND lft>=".$lft." AND rght<=".$rght." AND meeting_id=".$meeting_id." ORDER BY lft");
    }

    //get the meeting_id, lft and rght of decision
    function getdetails($DecisionId) {
        $details = $this->query("SELECT meeting_id, lft, rght FROM decisions WHERE deleted=0 AND id=".$DecisionId);
        return $details[0]['decisions'];
    }

    function UpdateMoveUp($id,$total) {
        $this->query("UPDATE decisions SET lft=lft-".$total.", rght=rght-".$total." WHERE id=".$id, false);
    }

    function UpdateMoveDown($id, $total) {
        $this->query("UPDATE decisions SET lft=lft+".$total.", rght=rght+".$total." WHERE id=".$id, false);
    }
       
    /* 
    * Describe needupdating
    * take the taken status or needupdating data
    * @param $decision
    * @param $detail
    * @param $n (taken=0; needupdating=1)
    * @return $decision 
    */ 
    function needupdating($decision,$n){
        $type=array('User','Group');
        for($i=0;$i<2;++$i){
            $status_imp_id=set::extract($decision[$type[$i].'status'],'{n}.'.low($type[$i]).'_id');
            foreach ($decision[$type[$i]] as $k=>$imp) { 
                $yes=(in_array($imp['id'],$status_imp_id));
                if($yes==$n){
                    unset($decision[$type[$i]][$k]);
                }
            }
        }
        return $decision;
    }
    
     /* 
    * Describe takenTime
    * filter the unwanted information in takenlate and takenontime
    * @param $decision
    * @param $detail
    * @param $n (ontime =0; late=1)
    * @return $decision 
    */ 
    function takenTime($decision,$n){
        $type=array('User','Group');
        for($i=0;$i<2;++$i){
            foreach($decision[$type[$i].'status'] as $j=>$status){
                $yes=($status['action_date']<=$decision['Decision']['deadline']);
                if($yes==$n){
                    foreach ($decision[$type[$i]] as $k=>$imp) { 
                        if($imp['id']==$status[low($type[$i]).'_id']){
                            unset ($decision[$type[$i]][$k]); 
                        }
                    }
                    unset ($decision[$type[$i].'status'][$j]);
                }
            }
        }
        return $decision;
    }
    
    /* 
    * Describe unset_nonImpstatus
    * unset the status if the implementor no longer is implementor again
    * @param $decision
    * @param $detail
    * @return $decision 
    */ 
    function unset_nonImpstatus($decision){
        $type=array('User','Group');
        for($i=0;$i<2;++$i){
            $imp_id=set::extract($decision[$type[$i]],'{n}.id');
            foreach($decision[$type[$i].'status'] as $j=>$status){
                if(!(in_array($status[low($type[$i]).'_id'],$imp_id))){
                    unset($decision[$type[$i].'status'][$j]);
                }
            }
        }
        return $decision;
    }    
    
    function beforeSave(){
        if(!empty($this->data['Decision']['description'])){
            $a=$this->data['Decision']['description'];
            // convert h1-6 to strong
            $hfront=array('<h1>','<h2>','<h3>','<h4>','<h5>','<h6>');
            $hback=array('</h1>','</h2>','</h3>','</h4>','</h5>','</h6>');
            $a=str_replace($hfront,'<strong>',$a);
            $a=str_replace($hback,'</strong>',$a);
            // strip the page margin format
            while(strpos($a,'&lt;!--')){
                $b=strpos($a,'&lt;!--');
                $d=strpos($a,'--&gt;',$b);
                $a=str_replace(substr($a,$b,$d-$b+6),'',$a);
            }
            //strip the font-size format
            while(strpos($a,'font-size')){
                $c=strpos($a,'font-size');
                $d=strpos($a,';',$c);
                $a=str_replace(substr($a,$c,$d-$c+1),'',$a);
            }
            //keep it clean
            $a=str_replace('style=""','',$a);
            $a=str_replace('n >','n>',$a);
            $a=str_replace(array('<p></p>','<p>&nbsp;</p>','</span><span>','<span></span>'),'',$a);
            $this->data['Decision']['description']=$a;
        }
        return true;
    }
    
    //fix decision lft and rght
    function reordering($meeting_id){
        //find all decision in that meeting
        $this->recursive=-1;
        $meeting_decisions=$this->find('all',array('order'=>array('Decision.lft ASC'),'conditions'=>array('Decision.deleted'=>0,'Decision.meeting_id'=>$meeting_id)));
        
        //set the unique lft and rght 
        $order=set::extract($meeting_decisions,'{n}.Decision.lft');
        $order=array_merge($order,set::extract($meeting_decisions,'{n}.Decision.rght'));
        $no_have=count($order);
        $order=array_filter(array_unique($order));
        $no_need=$no_have-count($order);
        $max_order=$this->find('first',array('fields'=>array('Decision.rght'),'conditions'=>array('Decision.deleted'=>0),'order'=>array('Decision.rght Desc')));
        $m=$max_order['Decision']['rght'];
        while($no_need){
            $order[]=++$m;
            $no_need--;
        }
        rsort($order);
        
        //find the main decision
        $main_decisions=array();
        foreach($meeting_decisions as $d=>$decision){
            if(empty($decision['Decision']['parent_id']) || $decision['Decision']['parent_id']==0 ||$decision['Decision']['parent_id']==$decision['Decision']['id']){
                $main_decisions[]=$decision;
            }
        }
        
        $defaultstat=array('high'=>array(),'Decision'=>array(),'sub'=>array());
        $stat=$this->decisionStat($defaultstat,$main_decisions,array_pop($order));
        while(!empty($stat['Decision'])){
            $child=array();
            if(empty($stat['old'])){
                $child=$this->find('all',array('order'=>array('Decision.lft ASC'),'conditions'=>array('Decision.deleted'=>0,'Decision.parent_id'=>$stat['Decision']['id'],'Decision.meeting_id'=>$meeting_id,'Decision.id !='.$stat['Decision']['id'])));
            }
            if(!empty($child)){
                $stat=$this->decisionStat($stat,$child,array_pop($order));
            }else{
                if(!empty($stat['sub'][count($stat['high'])])){
                    $stat=$this->decisionStat_Sub($stat,array_pop($order),array_pop($order));
                }else{
                    $stat=$this->decisionStat_high($stat,array_pop($order));
                }
            }
            
        }
        
        $query2='';
        foreach($stat['saved'] as $d=>$dec){
            $this->query("UPDATE decisions SET lft=".$dec['lft'].", rght=".$dec['rght']." WHERE id=".$dec['id'].";");
        }
    }
    
    function decisionStat($stat,$decisions,$lft){
        $i=0;
        if(!empty($stat['Decision'])){
            $stat['high'][]=$stat['Decision'];
            unset($stat['Decision']);
        }
        $no=count($stat['high']);
        foreach($decisions as $d){
            if($i==0){
                $stat['Decision']['id']=$d['Decision']['id'];
                $stat['Decision']['lft']=$lft;
            }else{
                $stat['sub'][$no][$i-1]['id']=$d['Decision']['id'];
            }
            $i++;
        }
        if(!empty($stat['old'])){
            unset($stat['old']);
        }
        return $stat;
    }
    
    function decisionStat2($stat,$rght){
        $stat['Decision']['rght']=$rght;
        $stat['saved'][]=$stat['Decision'];
        unset($stat['Decision']);

        return $stat;
    }
    
    function decisionStat_Sub($stat,$rght,$lft){
        $stat=$this->decisionStat2($stat,$rght);
        $no=count($stat['high']);
        if(!empty($stat['sub'][$no])){
            $stat['Decision']=array_shift($stat['sub'][$no]);
            if(!empty($stat['old'])){
                unset($stat['old']);
            }
            $stat['Decision']['lft']=$lft;
        }
        return $stat;
    }
    
    function decisionStat_high($stat,$rght){
        $stat=$this->decisionStat2($stat,$rght);
        $stat['Decision']=array_pop($stat['high']);
        $stat['old']=1;
        return $stat;
    }
    
    function rearrange($ori,$result){
        $all=array_merge($ori['lft'],$ori['rght']);
        sort($all);
        $change=array_combine($all,$result);
        foreach($ori['id'] as $d=>$data){
            $decision_result['id']=$data;
            $decision_result['lft']=$change[$ori['lft'][$d]];
            $decision_result['rght']=$change[$ori['rght'][$d]];
            $this->save($decision_result);
        }
    }
    
}
?>
